package thread;

import java.util.Scanner;

public class Demo10 {
    static class Counter {
        // 为了使线程能够感知到变量的变化，加上关键字volatile保证变量的可见性！！
        //volatile public int count = 0;

        // 再次进行改写
        public int count = 0;
    }

    public static void main(String[] args) {
        Counter counter = new Counter();
        Thread t = new Thread() {
            @Override
            public void run() {
                // 此时只是读内存操作 load， 然后在寄存器中进行比较compare
                // load消耗时间长，并且慢compare 3-4个数量级！！
                // 因为load比compare慢太多，编译器就想办法偷懒：
                // 此时我频繁执行load，并且load的结果是一样的（没人修改这个结果），就干脆只计算一次load，
                // 后续就直接进行compare而并不重新读取内存！
                while (counter.count==0) {
                    // 此时：其实虽然变量没有被volatile修饰，没有可见性，
                    // 但是该线程依旧是可以读取到变化后的变量值的，依旧可以结束该线程的循环
                    try {
                        Thread.sleep(1000);  // 进行休眠
                        // 一秒钟读取一次内存，这对于CPU来说又不优化已经没啥提升意义了
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("t线程运行结束");
            }
        };

        t.start();

        // 但是，此时如果再来一个线程修改了count的值，那胡怎样呢？
        Thread t2 = new Thread(() -> {
            System.out.println("请输入一个int：");
            Scanner in = new Scanner(System.in);
            counter.count = in.nextInt();
        });
        t2.start();

        // 此时预期输出与实际输出并不相符：
        // t2把count修改了之后对于t线程其实是不会又影响的，所以t也就不会执行结束
        // 因为t线程已经被优化成了不再读取内存，只读一次
        // 即：t2把内存改了，但是t没有感知到，这就是内存可见性问题！！
    }
}
